#pragma once
class CCodeGenerator
{
public:
	CCodeGenerator();
	~CCodeGenerator();

	void SetIsSubProgram(bool value);

	void AddIntVariable(std::string const & identifier);
	void AddArrayVariable(std::string const & identifier, std::string const & length);

	void AddAssignmentCommand(std::string const & receiver, std::string const & source);
	void AddAssignmentCommand(std::string const & receiver);
	
	void GeneratePrintCommand(std::string const & value);

	void MoveToRegister(std::string const & value);
	void GenerateAdditionCommand();
	void GenerateSubtractionCommand();
	void GenerateMultiplicationCommand();
	void GenerateDivisionCommand();
	void Invert();

	void SaveIdOrIntLiteral(std::string const & id);
	void MoveResultInOperand1();
	void AddLogOrOperation();
	void AddLogOperationLess();
	void AddLogOperationLessOrEqual();
	void AddLogAndOperation(std::string const & id);

	void AddJmpForIfElseStmt();
	void AddElseStmtLabel();
	void AddStmtsEndLabel();
	void IfElseStmtFinished();

	void AddWhileLabel();
	void AddJmpOnWhileLabel();

	void SetValue(std::string const & arr, std::string const & index, std::string const & value);
	void GetValue(std::string const & arr, std::string const & index);

	void AddSubprogramHeader(std::string const & name);
	void AddSubProgramEnd();

	void AddIntLocalVariable(std::string const & var);

	void PrepareRegisters();
	void CallSubProgram(std::string const & subProgName);
	void Copy(std::string const & op1, std::string const & op2);
	void MoveToStack(std::vector<std::string> & params);
	void ClearStack(std::string const & bytesCount);

	void MoveResultInOperand2(std::string const & res);

	std::string GetAssemblerProgram();
	void GenerateExecutableFile(std::string const & outputFileName = "output");

private:
	void Init();
	std::string GetDataSegment();
	void CreateAsmFile(std::string const & outputFileName);

	std::string GetTmlLabel(bool nextLabel = false) const;
	std::string GetElseLabel() const;
	std::string GetPrintLabel() const;
	std::string GetStmtsEndLabel() const;
	std::string GetWhileLabel() const;
	std::string GetRegister();
	void ReleaseRegister();

	std::string m_subPrograms;
	std::string m_stackSegment;
	std::string m_codeSegment;
	std::string m_exeProgramHeader;
	std::string m_programCode;
	std::string m_programEnd;

	int m_inStack;
	bool m_isSubProgram;

	unsigned m_whileCounter;
	unsigned m_tmpLabelCounter;
	unsigned m_printLabelsCounter;
	unsigned m_ifElseLabelsCounter;
	unsigned m_stmtsEndLabelsCounter;

	std::vector<std::string> m_variables;
	std::map<std::string, bool> m_registers;
	std::vector<std::string> m_usedRegisters;
};
